package cn.com.duiba.millionaire.center.biz.service.impl;

import cn.com.duiba.millionaire.center.api.cache.UserStatus;
import cn.com.duiba.millionaire.center.api.msg.SubmitAnswerMsg;
import cn.com.duiba.millionaire.center.biz.service.UserStatusInfoService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.javatuples.Pair;
import org.javatuples.Triplet;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by zzy on 2018/1/22.
 */
@Service
public class UserStatusInfoServiceImpl implements UserStatusInfoService {
    @Resource(name = "redisTemplate")
    private RedisTemplate<String, UserStatus> redisTemplate;

    /**
     *
     * @param mappedCids key:活动id,value:用户id集合
     * @return key1:用户id,key2:活动id
     */
    @Override
    public Map<Long, Map<Long, UserStatus>> batchFind(Map<Long, Set<Long>> mappedCids) {
        if (MapUtils.isEmpty(mappedCids)) {
            return Collections.emptyMap();
        }
        Set<String> keys = buildKeys(mappedCids);
        List<UserStatus> userStatusList = redisTemplate.opsForValue().multiGet(keys);
        if (CollectionUtils.isEmpty(userStatusList)) {
            return Collections.emptyMap();
        }
        Map<Long, Map<Long, UserStatus>> mappedUserStatus = new HashMap<>();
        for (UserStatus userStatus : userStatusList) {
            if (userStatus == null) {
                continue;
            }
            Map<Long, UserStatus> userStatusMap = mappedUserStatus.get(userStatus.getActivityId());
            if (userStatusMap == null) {
                userStatusMap = new HashMap<>();
                mappedUserStatus.put(userStatus.getActivityId(), userStatusMap);
            }
            userStatusMap.put(userStatus.getConsumerId(), userStatus);
        }
        return mappedUserStatus;
    }

    /**
     * 将用户标记为观看模式
     *
     * @param mappedCids key:活动id,value:用户id集合
     */
    @Override
    public void markFail(Map<Long, Set<Long>> mappedCids) {
        if (MapUtils.isEmpty(mappedCids)) {
            return;
        }
        List<String> keys = new ArrayList<>();
        Map<String, Pair<Long, Long>> keyMap = new HashMap<>();
        for (Map.Entry<Long, Set<Long>> entry : mappedCids.entrySet()) {
            for (Long cid : entry.getValue()) {
                String key = UserStatus.generateCacheKey(entry.getKey(), cid);
                keys.add(key);
                keyMap.put(key, Pair.with(entry.getKey(), cid));
            }
        }

        List<UserStatus> userStatusForUpdate = new ArrayList<>();
        List<UserStatus> userStatuses = redisTemplate.opsForValue().multiGet(keys);
        for (int i = 0; i < userStatuses.size(); i++) {
            UserStatus userStatus = userStatuses.get(i);
            if (userStatus == null) {
                Pair<Long, Long> pair = keyMap.get(keys.get(i));
                Long activityId = pair.getValue0();
                Long cid = pair.getValue1();
                userStatus = new UserStatus();
                userStatus.setActivityId(activityId);
                userStatus.setConsumerId(cid);
            }
            userStatus.setShowMode(true);
            userStatusForUpdate.add(userStatus);
        }

        batchUserStatusRedis(userStatusForUpdate);
    }


    /**
     * 用户消费复活卡
     *
     * @param mappedMsg
     */
    @Override
    public void consumeRenascenceCard(Map<Long, Set<SubmitAnswerMsg>> mappedMsg) {
        if (MapUtils.isEmpty(mappedMsg)) {
            return;
        }
        List<String> keys = new ArrayList<>();
        Map<String, Triplet<Long, Long,Integer>> keyMap = new HashMap<>();
        for (Map.Entry<Long, Set<SubmitAnswerMsg>>entry : mappedMsg.entrySet()) {
            for (SubmitAnswerMsg msg : entry.getValue()) {
                if(null==msg){
                  continue;
                }
                String key = UserStatus.generateCacheKey(entry.getKey(), msg.getConsumerId());
                keys.add(key);
                keyMap.put(key, Triplet.with(entry.getKey(), msg.getConsumerId(),msg.getQuestionIndex()));
            }
        }
        List<UserStatus> userStatusForUpdate = new ArrayList<>();
        List<UserStatus> userStatuses = redisTemplate.opsForValue().multiGet(keys);
        for (int i = 0; i < userStatuses.size(); i++) {
            UserStatus userStatus = userStatuses.get(i);
            Triplet<Long, Long, Integer> triplet = keyMap.get(keys.get(i));
            if (null==userStatus) {
                userStatus = new UserStatus();
                userStatus.setActivityId(triplet.getValue0());
                userStatus.setConsumerId(triplet.getValue1());
                userStatus.setShowMode(false);
            }
            List<Integer> reliveQuestionIndexList = userStatus.getReliveQuestionIndexList();
            reliveQuestionIndexList.add(triplet.getValue2());
            userStatus.setReliveQuestionIndexList(reliveQuestionIndexList);
            userStatus.setRenascenceCount(userStatus.getRenascenceCount()+1);
            userStatusForUpdate.add(userStatus);
        }

        batchUserStatusRedis(userStatusForUpdate);
    }

    private void batchUserStatusRedis(List<UserStatus> userStatusForUpdate){
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            RedisSerializer<Object> keyS = (RedisSerializer<Object>) redisTemplate.getKeySerializer();
            RedisSerializer<Object> valueS = (RedisSerializer<Object>) redisTemplate.getValueSerializer();
            for (UserStatus userStatus : userStatusForUpdate) {
                byte[] keyByte = keyS.serialize(UserStatus.generateCacheKey(userStatus.getActivityId(), userStatus.getConsumerId()));
                connection.set(keyByte, valueS.serialize(userStatus));
                connection.expire(keyByte,86400);
            }
            return null;
        });
    }

    private Set<String> buildKeys(Map<Long, Set<Long>> mappedCids) {
        Set<String> keys = new HashSet<>();
        for (Map.Entry<Long, Set<Long>> entry : mappedCids.entrySet()) {
            Long activityId = entry.getKey();
            for (Long cid : entry.getValue()) {
                keys.add(UserStatus.generateCacheKey(activityId, cid));
            }
        }
        return keys;
    }

}
